/*
 * Parsing the CIF file for inclusion as sublayout.
 *
 * Copyright (c) 2006 Xaveer Leijtens
 *
 * This file is part of libMask.
 *
 * libMask is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * libMask is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with libMask.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <string.h>
#include "mask.h"

#define BUFLEN 4096

typedef struct map_linked_list {
  int fr;
  int to;
  struct map_linked_list *next;
} map_llist;


void add_map(map_llist **head, int fr, int to) {
  map_llist *tmp;

  if ((tmp = (map_llist *)malloc(sizeof(*tmp))) == NULL) {
    fprintf(stderr, "Failed to allocate memory for sublayout calls.\n");
    exit(0);
  }
  tmp->fr = fr;
  tmp->to = to;
  tmp->next = *head;
  *head = tmp;
}

int laynummap(const int fr, const struct laynummap *nummap)
{
  const struct laynummap *nmap;

  if (nummap == NULL) return fr;
  for (nmap = nummap; nmap->fr > 0; nmap++) {
    if (nmap->fr == fr) {
      return nmap->to;
  } }
  return fr;
}

const char *layoutmap(const char *fr, const struct layoutmap *submap)
{
  const struct layoutmap *smap;

  if (submap == NULL) return fr;
  for (smap = submap; smap->fr != NULL; smap++) {
    if (strcasecmp(smap->fr, fr) == 0) {
      return smap->to;
  } }
  return fr;
}

void sublayout_input(
    const char *file,               /* The name of the file to be included */
    const struct laynummap *nummap, /* The layer number mapping */
    const struct layoutmap *submap) /* The (sub)layout name mapping */
{
  FILE *fpi, *fpo = NULL;
  char buf[BUFLEN];
  char *b;
  short DS;
  int fr, u, v;
  map_llist *DS_list = NULL;
  map_llist *DS_ptr;
  char fln[BUFLEN];
  int layoutnum;

  /* just stop: it is no longer supported with mask V6 (yet) */
  fprintf(stderr, "sublayout_input() is no longer supported in this version of the mask\nlibrary.\n  Aborting...\n");
  exit(1);

  if (mode&FLATTENED) {
    fprintf(stderr, "Mask layouts which include files cannot be flattened by this library.\n  Aborting...\n");
    exit(1);
  }

#ifdef DEBUG
  const struct laynummap *n;
  const struct layoutmap *s;

  fprintf(stderr, "Sublayout input file name '%s'.\n", file);
  fprintf(stderr, "The layer number mapping:\n");
  for (n = nummap; n->fr > 0; n++)
    fprintf(stderr, "  Layer %03d -> %30d\n", n->fr, n->to);
  fprintf(stderr, "The sublayout name mapping:\n");
  for (s = submap; s->fr != NULL; s++)
    fprintf(stderr, "  Layout %s -> %s\n", s->fr, s->to);
#endif

  if ((fpi = fopen(file, "r")) == NULL) {
    fprintf(stderr, "Can't open file '%s'.\n", file);
    exit(1);
  }
  /* Simple parser (somewhat CleWin specific) */
  /* skip first comment section */
  while ((b = fgets(buf, BUFLEN, fpi)) != NULL && *b == '(') continue;
  /* skip first Layer definitions */
  if (*b == 'L') while ((b = fgets(buf, BUFLEN, fpi)) != NULL && *b == 'L') continue;
  /* Copy rest literally, but replace the symbol definitions with a new
   * sequence number and layer numbers and layout names from maps.
   */
  DS = FALSE;
  for (; b != NULL; b = fgets(buf, BUFLEN, fpi)) {
    if (*b == 'D' || *b == 'd') { /* Definition */
      b++;
      if (*b == 'S' || *b == 's') { /* Start */
	DS = TRUE;
        fpo = NULL;
        /* Definition start: should be followed by the layout name, which
         * will trigger the start of writing the file. Definitions without
         * names will not be written.
         */
	sscanf(b+1, "%d %d %d;", &fr, &u, &v);
      } else if (*b == 'F' || *b == 'f') { /* Finish this definition */
	DS = FALSE;
	if (fpo) fputs(buf, fpo);
        fclose(fpo);
        fpo = NULL;
      }
    } else if (*b == '9') { /* Name */
      if (strchr(b+2, ';') != NULL) {
	*strchr(b+2, ';') = '\0';
      } else {
	fprintf(stderr, "Syntax error in included CIF file %s:\n  missing semicolon, read '%s'.\n",
	  file, b);
	exit(0);
      }
      layoutnum = msk_add_sublayout(layoutmap(b+2, submap),
        &sublayout_file);
      add_map(&DS_list, fr, layoutnum); /* add to map list */
      sprintf(fln, "%s%03d.cif", TMP_NAME_TMPL, layoutnum);
      if ((fpo = fopen(fln, "w")) == NULL) {
        fprintf(stderr, "Can't open file '%s'.\n", fln);
        exit(1);
      }
      if (fpo) fprintf(fpo, "DS%d %d %d;\n", layoutnum+1, u, v);
      if (fpo) fprintf(fpo, "9 %s;\n", layoutmap(b+2, submap));
    } else if (*b == 'L' || *b == 'l') { /* Layer number */
      sscanf(b+3, "%d;", &fr);
      if (fpo) fprintf(fpo, "L L%03d;\n", laynummap(fr, nummap));
    } else if (*b == 'C' || *b == 'c') {
      if (DS == FALSE) {
        /* It is the main call: make it a symbol definition. */
        add_map(&DS_list, fr, layoutnum); /* add to map list */
        sprintf(fln, "%s%03d.cif", TMP_NAME_TMPL, this_layout);
        if ((fpo = fopen(fln, "w")) == NULL) {
          fprintf(stderr, "Can't open file '%s'.\n", fln);
          exit(1);
        }
        if (fpo) fprintf(fpo, "DS%d 1 10;\n9 %s;\n", this_layout+1,
          layouts[this_layout].name);
	DS = TRUE;
      }
      sscanf(b+2, "%d ", &fr);
      if ((b = strchr(b+2, ' ')) == NULL) b = strchr(buf+2, ';');
      for (DS_ptr = DS_list; DS_ptr != NULL; DS_ptr = DS_ptr->next) {
	if (DS_ptr->fr == fr) {
	  if (fpo) fprintf(fpo, "C %d%s", DS_ptr->to+1, b);
	  break;
      } }
      if (DS_ptr == NULL) {
	/* Called from other sublayout before definition: add now */
        fprintf(stderr, "Oops: called before definition. Dying...\n");
        fprintf(stderr, "  buffer: '%s'\n", b);
        exit(1);
	//add_map(&DS_list, fr, ++sub_sublayout); /* add to map list */
	//if (fpo) fprintf(MASK, "C %d%s", sub_sublayout+1, b);
      }
    } else if (*b == 'E' || *b == 'e') {
      if (fpo) fprintf(fpo, "DF;\n");
      fclose(fpo);
      fpo = NULL;
    } else {
      if (fpo) fputs(buf, fpo);
  } }
  fclose(fpi);
}

/* Example of use */
/*
int main() {
  const struct laynummap n[] = {
    { 1,  5},
    {12, 34},
    { 2,  3},
    { 4,  2},
    { 8,  9},
    END_LAYNUMMAP
  };
  const struct layoutmap l[] = {
    { "aap", "noot" },
    { "wim", "zus" },
    { "piet", "klaas" },
    { "layout", "Nieuw" },
    { "mainSyMbol", "Hoofd" },
    END_LAYOUTMAP
  };

  sublayout_input("cif/hier_ex.cif", "File_1", n, l);
}
*/
